using DG.Tweening;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class QuiQuiObj : MonoBehaviour
{
    public enum LifeCycleType
    {
        None,
        Baby,
        Boy,
        Youth,
        Prim,
        Middle,
        Old,
    }
    public enum DieWay
    {
        None,
        Hungry,
        Age,
        Kill,
        Tired,
    }
    [SerializeField]
    QuiQuiData m_StaticData;

    public QuiQuiBase baseConfig { get { return m_StaticData.Base[0]; } }
    public float hungryVaue { get { return m_HungryValue; } }
    public UnityEvent<Collider2D> onTriggerEnterCallback { get { return m_OnTriggerEnterCallback; } }
    public UnityEvent<QuiQuiObj, float> onDamagedCallback { get { return m_OnDamagedCallback; } }
    public float lifeScale { get { return m_Life / baseConfig.lifeTime; } }
    public bool isAttacking { get { return m_IsAttacking; } set { m_IsAttacking = value; } }
    public List<IntersectionObject> foucsObjects { get { return m_FoucsObj; } }
    public TrailRenderer m_ShitDragMark;
    public float scale
    {
        get
        {
            var lifeCycleData = GetLifeCycleConfig(m_LifeCycle);
            return lifeCycleData.sizeScale + m_ExternalSize;
        }
    }
    public IntersectionObject intersectingObj { get { return m_IntersectionObj; } set { m_IntersectionObj = value; } }
    public IntersectionObject takingObj { get { return m_TakingObj; } }
    public LifeCycleType lifeCycle
    {
        get { return m_LifeCycle; }
    }

    LifeCycleType m_LifeCycle = LifeCycleType.None;

    Rigidbody2D m_RigidBody;
    [SerializeField]
    List<IntersectionObject> m_FoucsObj = new List<IntersectionObject>();

    UnityEvent<Collider2D> m_OnTriggerEnterCallback = new UnityEvent<Collider2D>();
    UnityEvent<QuiQuiObj, float> m_OnDamagedCallback = new UnityEvent<QuiQuiObj, float>();

    float m_Life = 0;
    float m_HungryValue = 0;
    WaveEffect m_WaveEffect;
    Vector2 m_Direction;

    bool m_IsAttacking = false;
    float m_AttackPower = 0;
    Vector3 m_AimDir;
    float m_CanDamageOtherCount = 0;
    [SerializeField]
    float m_AttackPhycicsPower = 200;
    float m_ExternalSize = 0;

    float m_ShitStore = 0;
    float m_ShitStoreMax = 30;
    bool m_IsIntersecting = false;
    float m_ShitDragMarkQuantity = 0;
    IntersectionObject m_TakingObj;
    IntersectionObject m_IntersectionObj;
    float m_ExternalHungrayValue = 0;

    List<GameObject> m_StageFaces = new List<GameObject>();

    private void Awake()
    {
        m_WaveEffect = transform.GetComponentInChildren<WaveEffect>();
        m_ShitDragMark = GetComponent<TrailRenderer>();

        var faces = transform.Find("StageFace");
        for (int i = 0; i < faces.childCount; ++i)
        {
            var child = faces.GetChild(i);
            m_StageFaces.Add(child.gameObject);
        }
    }
    void Start()
    {
        m_RigidBody = GetComponent<Rigidbody2D>();
        m_ShitDragMark.material.SetTextureScale("_MainTex", new Vector2(1, 5));
    }
    int CalcNewCycleStage()
    {
        return (int)Mathf.Min(5, (m_Life / 30f + 1));
    }
    QuiQuiLifeCycleData CheckCycleStage()
    {
        QuiQuiLifeCycleData lifeCycleData = null;
        var newCycleStage = CalcNewCycleStage();
        if (newCycleStage != (int)m_LifeCycle)
        {
            m_LifeCycle = (LifeCycleType)newCycleStage;
            lifeCycleData = GetLifeCycleConfig(m_LifeCycle);
            transform.DOScale(scale, 0.5f);
            DOVirtual.DelayedCall(0.5f, () =>
            {
                var objs = transform.GetComponentsInChildren<IntersectionObject>();
                foreach (var i in objs)
                {
                    i.transform.localScale = Vector3.one;
                }
            });

            foreach (var i in m_StageFaces)
            {
                i.gameObject.SetActive(false);
            }
            m_StageFaces[(int)(m_LifeCycle - 1)].gameObject.SetActive(true);
        }
        else
        {
            lifeCycleData = GetLifeCycleConfig(m_LifeCycle);
        }
        return lifeCycleData;
    }
    // Update is called once per frame
    void Update()
    {
        m_ShitStore += Time.deltaTime;
        if (m_ShitStore > m_ShitStoreMax)
        {
            m_ShitStore = 0;
            var shitObj = IntersectionObjManager.Instance.CreateObj(IntersectionObjManager.IntersectionObjType.Shit).GetComponent<ShitObj>();
            shitObj.transform.position = transform.position;
            shitObj.SetColliderEnabled(false);
            shitObj.transform.DOMove(transform.position + -transform.up * 0.5f, 0.4f);
            if (gameObject.GetComponent<PlayerControle>())
                SoundManager.Instance.PlaySound(SoundManager.SoundType.DropShit, gameObject);
            DOVirtual.DelayedCall(1, () =>
            {
                shitObj.SetColliderEnabled(true);
            });
        }
        if (m_CanDamageOtherCount > 0)
            m_CanDamageOtherCount -= Time.deltaTime;
        var lifeCycleData = CheckCycleStage();
        m_HungryValue -= Time.deltaTime * lifeCycleData.hungrySpeedScale;
        m_Life += Time.deltaTime;

        m_WaveEffect.waveHeight = m_HungryValue / baseConfig.maxHungryValue;
        m_WaveEffect.color = Color.Lerp(Color.white, Color.gray, m_Life / baseConfig.lifeTime);
        if (m_HungryValue < 0)
        {
            WorldManager.Instance.CycleQuiQui(gameObject, DieWay.Hungry);
            return;
        }
        if (m_Life > baseConfig.lifeTime)
        {
            WorldManager.Instance.CycleQuiQui(gameObject, DieWay.Age);
            return;
        }

        if (m_IsAttacking)
        {
            m_AttackPower += Time.deltaTime * 5;
            transform.localScale = new Vector3(scale, scale - Mathf.Min(0.5f, m_AttackPower / 1 * 0.5f) * scale, 1);
        }
        else
        {
            if (m_AttackPower > 0.2f)
            {
                m_AttackPower = 0;
                transform.localScale = new Vector3(scale, scale, 1);
                m_RigidBody.AddForce(transform.up * lifeCycleData.attackPhysicsPower, ForceMode2D.Impulse);
                m_CanDamageOtherCount = 0.5f;

                if (gameObject.GetComponent<PlayerControle>())
                    SoundManager.Instance.PlaySound(SoundManager.SoundType.Rust, gameObject);
                m_HungryValue -= 3;
                if (m_HungryValue <= 0)
                {
                    WorldManager.Instance.CycleQuiQui(gameObject, DieWay.Tired);
                }
            }
        }
    }
    public void RandomLife()
    {
        m_Life = Random.Range(0, baseConfig.lifeTime / 2f);
    }
    public void DoIntersection()
    {
        if (m_TakingObj)
            return;
        for (int i = 0; i < m_FoucsObj.Count; ++i)
        {
            if (m_FoucsObj[i].isSupportIntersection && m_FoucsObj[i].CanIntersection())
            {
                m_FoucsObj[i].OnIntersection(this);
            }
        }
    }
    public void DoTake()
    {
        if (m_TakingObj || m_IntersectionObj)
            return;
        for (int i = 0; i < m_FoucsObj.Count; ++i)
        {
            if (m_FoucsObj[i].isSupportTake)
            {
                m_FoucsObj[i].OnTake(this);
                m_TakingObj = m_FoucsObj[i];
                break;
            }
        }
    }
    public void DoPlace()
    {
        if (m_TakingObj)
        {
            m_TakingObj.OnPlace();
            m_TakingObj = null;
        }
    }
    public void OnCreate()
    {
        m_HungryValue = baseConfig.maxHungryValue;
        m_Life = 0;
        m_ExternalSize = 0;
        m_ShitStore = Random.Range(0, 10);
        m_FoucsObj.Clear();
        m_ExternalHungrayValue = 0;
    }
    public QuiQuiLifeCycleData GetLifeCycleConfig(LifeCycleType lifeCycleType)
    {
        if (lifeCycleType <= 0 || (int)lifeCycleType > 5)
        {
            Debug.Log("miao");
        }
        return m_StaticData.LifeCycle[(int)lifeCycleType - 1];
    }

    public void Move(Vector2 direction)
    {
        m_Direction = Vector2.Lerp(m_Direction, direction, Time.deltaTime * 2);
        if (m_CanDamageOtherCount <= 0 && m_LifeCycle != LifeCycleType.None)
        {
            transform.rotation = Quaternion.LookRotation(-Vector3.forward, m_Direction);
            var lifeCycleData = GetLifeCycleConfig(m_LifeCycle);
            var distance = baseConfig.maxSpeed * lifeCycleData.moveSpeedScale * (m_IsAttacking ? 0.4f : 1f);

            float velocityByAge = (baseConfig.lifeTime - m_Life) > 20 ? 1f : (baseConfig.lifeTime - m_Life) / 20f;
            m_RigidBody.velocity = m_Direction * distance * velocityByAge;

            if (m_ShitDragMarkQuantity > 0)
            {
                m_ShitDragMarkQuantity -= distance * Time.deltaTime;
            }
            else
            {
                m_ShitDragMark.emitting = false;
            }
        }
    }
    public void Stand()
    {
        m_Direction = Vector3.zero;
    }

    public void Eat(float hungryValue, float growValue = 0)
    {

        m_ExternalSize += growValue;
        if (m_HungryValue + hungryValue > baseConfig.maxHungryValue)
            m_ExternalHungrayValue += m_HungryValue + hungryValue - baseConfig.maxHungryValue;
        m_HungryValue = Mathf.Min(m_HungryValue + hungryValue, baseConfig.maxHungryValue);

        if (m_ExternalHungrayValue > 30)
        {
            m_ExternalHungrayValue = 0;
            var quiqui = WorldManager.Instance.CreateQuiQui();
            quiqui.transform.position = transform.position;
            quiqui.transform.DOMove(transform.position + transform.right * 2, 0.4f);

            if (gameObject.GetComponent<PlayerControle>())
                SoundManager.Instance.PlaySound(SoundManager.SoundType.Born, gameObject);
            return;
        }
        if (gameObject.GetComponent<PlayerControle>())
            SoundManager.Instance.PlaySound(SoundManager.SoundType.EatSmallFood, gameObject);
    }
    public void BeDamaged(QuiQuiObj quiquiObj, float damage)
    {
        m_HungryValue = Mathf.Max(m_HungryValue - damage, 0);
        m_OnDamagedCallback.Invoke(quiquiObj, damage);

        m_WaveEffect.PlayDamagedEffect();
        if (damage / 3f > 2)
        {
            int dropFoodNum = (int)Random.Range(1f, damage / 2f);

            for (var i = 0; i < dropFoodNum; ++i)
            {
                var smallFood = IntersectionObjManager.Instance.CreateObj(IntersectionObjManager.IntersectionObjType.SmallFood).GetComponent<IntersectionObject>();
                smallFood.transform.position = transform.position;
                smallFood.transform.DOMove(transform.position + new Vector3(Random.Range(-3, 3), Random.Range(-3, 3), 0), 0.5f);
                smallFood.SetColliderEnabled(false);
                DOVirtual.DelayedCall(1f, () =>
                {
                    smallFood.SetColliderEnabled(true);
                });
            }
        }
        if (m_HungryValue <= 0)
        {
            WorldManager.Instance.CycleQuiQui(gameObject, DieWay.Kill);
        }
    }

    public void OnTriggerEnter2D(Collider2D collision)
    {
        // ����ȵ�ʺ��
        if (collision.gameObject.GetComponent<ShitObj>())
        {
            m_ShitDragMark.emitting = true;
            m_ShitDragMarkQuantity = 5;
        }


        m_OnTriggerEnterCallback.Invoke(collision);
        var foucsObj = collision.gameObject.GetComponent<IntersectionObject>();
        if (!foucsObj)
            return;
        m_FoucsObj.Add(foucsObj);

        var food = foucsObj as FoodObj;
        if (food && food.autoEat)
        {
            Eat(food.foodValue);
            IntersectionObjManager.Instance.CycleObj(food.gameObject);
        }
    }
    public void OnTriggerExit2D(Collider2D collision)
    {
        var foucsObj = collision.gameObject.GetComponent<IntersectionObject>();
        if (!foucsObj)
            return;
        m_FoucsObj.Remove(foucsObj);
    }
    public void OnCollisionEnter2D(Collision2D collision)
    {
        if (m_LifeCycle == LifeCycleType.None)
            return;
        var lifeCycleData = GetLifeCycleConfig(m_LifeCycle);
        var quiquiObj = collision.gameObject.GetComponent<QuiQuiObj>();
        if (m_CanDamageOtherCount > 0 && quiquiObj)
        {
            quiquiObj.BeDamaged(this, lifeCycleData.attackPower * transform.localScale.x);
        }
    }
}
